package com.xyht.medicine_management_system.common.commonReturn;

import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

/**
 * @author Ikaros
 * @date 2020/1/26 18:24
 */
@RestControllerAdvice
@Slf4j
public class ExceptionCatch {

  /** 使用EXCEPTIONS存放异常类型和错误代码的映射， ImmutableMap的特点的一旦创建不可改变，并且线程安全 */
  private static ImmutableMap<Class<? extends Throwable>, ResponseResult> EXCEPTIONS;

  /** 使用builder来构建一个异常类型和错误代码的异常 */
  private static ImmutableMap.Builder<Class<? extends Throwable>, ResponseResult> builder =
      ImmutableMap.builder();

  static {
    // 在这里加入一些基础的异常类型判断
    builder.put(HttpMessageNotReadableException.class, CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
    builder.put(MaxUploadSizeExceededException.class, CommonResult.failed(CommonCodeEnum.FILE_SIZE_LIMIT_EXCEEDED));
    builder.put(DataIntegrityViolationException.class, CommonResult.failed(CommonCodeEnum.DATA_OVER_LENGTH_EXCEPTION));
    builder.put(ClientAbortException.class, CommonResult.failed(CommonCodeEnum.SERVER_ERROR));
    builder.put(AsyncRequestTimeoutException.class, CommonResult.failed(CommonCodeEnum.REQUEST_TIMEOUT));
    builder.put(DuplicateKeyException.class, CommonResult.failed(CommonCodeEnum.DATA_EXIST));
    builder.put(MethodArgumentTypeMismatchException.class, CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
    builder.put(MissingServletRequestParameterException.class, CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
    builder.put(MethodArgumentNotValidException.class, CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
    builder.put(NumberFormatException.class, CommonResult.failed(CommonCodeEnum.INVALID_PARAM_FORMAT));
  }

  @ExceptionHandler(CustomException.class)
  public ResponseResult customException(CustomException e) {
    log.error("catch commonReturn : {}", e.getMessage());
    return e.getCommonResult();
  }
  @ExceptionHandler(EmptyResultDataAccessException.class)
  public ResponseResult customException(EmptyResultDataAccessException e) {
    log.error("catch commonReturn : {}", e.getMessage());
    // DAO访问数据为空
    // TODO
    return CommonResult.success();
  }

  @ExceptionHandler(Exception.class)
  public ResponseResult exception(Exception exception) {
    // 记录日志
    log.error("catch commonReturn:{}", exception.getClass() + "------" + exception.getMessage());
    if (EXCEPTIONS == null) {
      EXCEPTIONS = builder.build();
    }
    final ResponseResult resultCode = EXCEPTIONS.get(exception.getClass());
    ResponseResult commonResult = null;
    if (resultCode != null) {
      commonResult = resultCode;
    } else {
      commonResult = CommonResult.failed(CommonCodeEnum.SERVER_ERROR);
    }
    return commonResult;
  }
}
